package cn.lblbc.downloadlib;

import android.content.Context;
import android.util.Log;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.Transformations;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import cn.lblbc.downloadlib.database.DatabaseManager;
import cn.lblbc.downloadlib.database.DownloadFileEntity;
import cn.lblbc.downloadlib.database.DownloadTaskEntity;
import cn.lblbc.downloadlib.database.DownloadTaskEntityMapper;

/**
 * 下载管理器 - 对外统一入口
 */
public class DownloadManager {
    private static final String TAG = "DownloadManager";
    private static volatile DownloadManager sInstance;
    private Context mContext;
    private DownloadConfig mConfig;
    private DatabaseManager mDatabaseManager;
    private DownloadScheduler mScheduler;
    private ExecutorService mExecutorService;

    private DownloadManager() {
        mExecutorService = Executors.newFixedThreadPool(3);
    }

    public static void init(Context context, DownloadConfig config) {
        if (sInstance == null) {
            synchronized (DownloadManager.class) {
                if (sInstance == null) {
                    sInstance = new DownloadManager();
                    sInstance.mContext = context.getApplicationContext();
                    sInstance.mConfig = config;
                    sInstance.mDatabaseManager = DatabaseManager.getInstance();
                    sInstance.mDatabaseManager.init(context);
                    sInstance.mScheduler = DownloadScheduler.getInstance(config);
                    Log.d(TAG, "init: DownloadManager initialized with config: " + config.getConcurrentTaskNum() + 
                        " concurrent tasks, chunk size: " + config.getChunkSize());
                }
            }
        }
    }

    public static DownloadManager getInstance() {
        if (sInstance == null) {
            throw new IllegalStateException("DownloadManager not initialized. Call init() first.");
        }
        return sInstance;
    }

    public Context getContext() {
        return mContext;
    }

    public DownloadConfig getConfig() {
        return mConfig;
    }

    /**
     * 提交下载任务
     * @param task 下载任务
     * @return 任务操作结果
     */
    public TaskOperateResult submitTask(DownloadTask task) {
        try {
            Log.d(TAG, "submitTask: Submitting task with package: " + task.getPackageName());
            // 将DownloadTask转换为DownloadTaskEntity并保存到数据库
            DownloadTaskEntity entity = new DownloadTaskEntity();
            long taskId = task.getTaskId() > 0 ? task.getTaskId() : System.currentTimeMillis();
            entity.setTaskId(taskId);
            entity.setPackageName(task.getPackageName());
            entity.setTotalSize(task.getTotalSize());
            entity.setDownloadedSize(task.getDownloadedSize());
            entity.setStatus(task.getStatus());
            entity.setIsWifiOnly(task.isWifiOnly() ? 1 : 0);
            entity.setCreateTime(task.getCreateTime());
            entity.setUpdateTime(task.getUpdateTime());
            entity.setExtraInfo(task.getExtraInfo());
            
            // 在后台线程保存到数据库
            mDatabaseManager.getDatabase().downloadTaskDao().insertTask(entity);
            Log.d(TAG, "submitTask: Task inserted into database with ID: " + entity.getTaskId());
            
            // 保存文件信息到数据库
            saveTaskFiles(taskId, task.getFiles());
            
            // 启动下载任务
            startDownload(entity.getTaskId());
            
            return new TaskOperateResult(true, "Task submitted successfully", entity.getTaskId());
        } catch (Exception e) {
            Log.e(TAG, "submitTask: Error submitting task", e);
            e.printStackTrace();
            return new TaskOperateResult(false, "Failed to submit task: " + e.getMessage(), -1);
        }
    }
    
    /**
     * 保存任务文件信息到数据库
     * @param taskId 任务ID
     * @param files 文件列表
     */
    private void saveTaskFiles(long taskId, List<DownloadFileInfo> files) {
        Log.d(TAG, "saveTaskFiles: Saving " + (files != null ? files.size() : 0) + " files for task ID: " + taskId);
        if (files == null || files.isEmpty()) {
            Log.d(TAG, "saveTaskFiles: No files to save");
            return;
        }
        
        try {
            List<DownloadFileEntity> fileEntities = new ArrayList<>();
            for (DownloadFileInfo fileInfo : files) {
                DownloadFileEntity fileEntity = new DownloadFileEntity();
                fileEntity.setFileId(fileInfo.getFileId() > 0 ? fileInfo.getFileId() : System.currentTimeMillis());
                fileEntity.setTaskId(taskId);
                fileEntity.setFileUrl(fileInfo.getFileUrl());
                fileEntity.setFileName(fileInfo.getFileName());
                fileEntity.setFileType(fileInfo.getFileType());
                fileEntity.setFileSize(fileInfo.getFileSize());
                fileEntity.setDownloadedSize(fileInfo.getDownloadedSize());
                fileEntity.setStatus(fileInfo.getStatus());
                fileEntity.setLocalPath(fileInfo.getLocalPath());
                fileEntity.setMd5(fileInfo.getMd5());
                fileEntity.setCreateTime(fileInfo.getCreateTime() > 0 ? fileInfo.getCreateTime() : System.currentTimeMillis());
                fileEntity.setUpdateTime(fileInfo.getUpdateTime() > 0 ? fileInfo.getUpdateTime() : System.currentTimeMillis());
                fileEntities.add(fileEntity);
            }
            
            mDatabaseManager.getDatabase().downloadFileDao().insertFiles(fileEntities);
            Log.d(TAG, "saveTaskFiles: Saved " + fileEntities.size() + " files to database");
        } catch (Exception e) {
            Log.e(TAG, "saveTaskFiles: Error saving task files", e);
        }
    }
    
    /**
     * 更新文件进度
     * @param fileId 文件ID
     * @param downloadedSize 已下载大小
     */
    public void updateFileProgress(long fileId, long downloadedSize) {
        mExecutorService.execute(() -> {
            try {
                mDatabaseManager.getDatabase().downloadFileDao().updateFileProgress(
                    fileId, downloadedSize, System.currentTimeMillis());
                Log.d(TAG, "updateFileProgress: Updated file progress, fileId: " + fileId + 
                    ", downloadedSize: " + downloadedSize);
            } catch (Exception e) {
                Log.e(TAG, "updateFileProgress: Error updating file progress", e);
            }
        });
    }
    
    /**
     * 更新任务进度
     * @param taskId 任务ID
     * @param fileDownloadedSize 文件已下载大小
     */
    public void updateTaskProgress(long taskId, long fileDownloadedSize) {
        mExecutorService.execute(() -> {
            try {
                mDatabaseManager.getDatabase().downloadTaskDao().updateTaskProgress(
                    taskId, fileDownloadedSize, System.currentTimeMillis());
                Log.d(TAG, "updateTaskProgress: Updated task progress, taskId: " + taskId + 
                    ", fileDownloadedSize: " + fileDownloadedSize);
            } catch (Exception e) {
                Log.e(TAG, "updateTaskProgress: Error updating task progress", e);
            }
        });
    }
    
    /**
     * 更新文件状态
     * @param fileId 文件ID
     * @param status 状态
     */
    public void updateFileStatus(long fileId, int status) {
        mExecutorService.execute(() -> {
            try {
                mDatabaseManager.getDatabase().downloadFileDao().updateFileStatus(
                    fileId, status, System.currentTimeMillis());
                Log.d(TAG, "updateFileStatus: Updated file status, fileId: " + fileId + 
                    ", status: " + status);
            } catch (Exception e) {
                Log.e(TAG, "updateFileStatus: Error updating file status", e);
            }
        });
    }
    
    /**
     * 更新任务状态
     * @param taskId 任务ID
     * @param status 状态
     */
    public void updateTaskStatus(long taskId, int status) {
        mExecutorService.execute(() -> {
            try {
                mDatabaseManager.getDatabase().downloadTaskDao().updateTaskStatus(
                    taskId, status, System.currentTimeMillis());
                Log.d(TAG, "updateTaskStatus: Updated task status, taskId: " + taskId + 
                    ", status: " + status);
            } catch (Exception e) {
                Log.e(TAG, "updateTaskStatus: Error updating task status", e);
            }
        });
    }
    
    /**
     * 启动下载任务
     * @param taskId 任务ID
     */
    public void startDownload(long taskId) {
        Log.d(TAG, "startDownload: Starting download for task ID: " + taskId);
        // 从数据库获取任务信息
        mExecutorService.execute(() -> {
            try {
                DownloadTaskEntity entity = mDatabaseManager.getDatabase()
                    .downloadTaskDao()
                    .getTaskById(taskId);
                
                if (entity != null) {
                    Log.d(TAG, "startDownload: Task found in database, creating DownloadTask object");
                    // 构造DownloadTask对象
                    DownloadTask task = new DownloadTask();
                    task.setTaskId(entity.getTaskId());
                    task.setPackageName(entity.getPackageName());
                    task.setTotalSize(entity.getTotalSize() != null ? entity.getTotalSize() : 0);
                    task.setDownloadedSize(entity.getDownloadedSize() != null ? entity.getDownloadedSize() : 0);
                    task.setStatus(entity.getStatus());
                    task.setWifiOnly(entity.getIsWifiOnly() == 1);
                    task.setCreateTime(entity.getCreateTime());
                    task.setUpdateTime(entity.getUpdateTime());
                    task.setExtraInfo(entity.getExtraInfo());
                    
                    // 从数据库获取文件信息并设置到task中
                    List<DownloadFileEntity> fileEntities = mDatabaseManager.getDatabase()
                        .downloadFileDao()
                        .getFilesByTaskId(taskId);
                    
                    Log.d(TAG, "startDownload: Found " + fileEntities.size() + " files for task ID: " + taskId);
                    List<DownloadFileInfo> files = new ArrayList<>();
                    for (DownloadFileEntity fileEntity : fileEntities) {
                        DownloadFileInfo fileInfo = new DownloadFileInfo();
                        fileInfo.setFileId(fileEntity.getFileId());
                        fileInfo.setTaskId(fileEntity.getTaskId());
                        fileInfo.setFileUrl(fileEntity.getFileUrl());
                        fileInfo.setFileName(fileEntity.getFileName());
                        fileInfo.setFileType(fileEntity.getFileType());
                        fileInfo.setFileSize(fileEntity.getFileSize());
                        fileInfo.setDownloadedSize(fileEntity.getDownloadedSize() != null ? fileEntity.getDownloadedSize() : 0);
                        fileInfo.setStatus(fileEntity.getStatus());
                        fileInfo.setLocalPath(fileEntity.getLocalPath());
                        fileInfo.setMd5(fileEntity.getMd5());
                        fileInfo.setCreateTime(fileEntity.getCreateTime());
                        fileInfo.setUpdateTime(fileEntity.getUpdateTime());
                        files.add(fileInfo);
                    }
                    task.setFiles(files);
                    
                    Log.d(TAG, "startDownload: Submitting task to scheduler");
                    // 提交任务到调度器
                    mScheduler.submitTask(task);
                } else {
                    Log.e(TAG, "startDownload: Task not found with ID: " + taskId);
                }
            } catch (Exception e) {
                Log.e(TAG, "startDownload: Error starting download for task ID: " + taskId, e);
            }
        });
    }

    /**
     * 异步提交下载任务
     * @param task 下载任务
     * @param callback 回调函数
     */
    public void submitTaskAsync(DownloadTask task, SubmitTaskCallback callback) {
        Log.d(TAG, "submitTaskAsync: Starting to submit task");
        mExecutorService.execute(() -> {
            try {
                Log.d(TAG, "submitTaskAsync: Running on background thread");
                // 将DownloadTask转换为DownloadTaskEntity并保存到数据库
                DownloadTaskEntity entity = new DownloadTaskEntity();
                long taskId = task.getTaskId() > 0 ? task.getTaskId() : System.currentTimeMillis();
                entity.setTaskId(taskId);
                entity.setPackageName(task.getPackageName());
                entity.setTotalSize(task.getTotalSize());
                entity.setDownloadedSize(task.getDownloadedSize());
                entity.setStatus(task.getStatus());
                entity.setIsWifiOnly(task.isWifiOnly() ? 1 : 0);
                entity.setCreateTime(task.getCreateTime());
                entity.setUpdateTime(task.getUpdateTime());
                entity.setExtraInfo(task.getExtraInfo());

                Log.d(TAG, "submitTaskAsync: Task data - package: " + task.getPackageName() + ", url: " + 
                    (task.getFiles().size() > 0 ? task.getFiles().get(0).getFileUrl() : "no files"));
                
                // 在后台线程保存到数据库
                mDatabaseManager.getDatabase().downloadTaskDao().insertTask(entity);
                Log.d(TAG, "submitTaskAsync: Task inserted into database with ID: " + entity.getTaskId());
                
                // 保存文件信息到数据库
                saveTaskFiles(taskId, task.getFiles());
                
                // 启动下载任务
                startDownload(entity.getTaskId());

                TaskOperateResult result = new TaskOperateResult(true, "Task submitted successfully", entity.getTaskId());
                
                // 在主线程中执行回调
                runOnUIThread(() -> {
                    Log.d(TAG, "submitTaskAsync: Calling callback on main thread");
                    callback.onResult(result);
                });
            } catch (Exception e) {
                Log.e(TAG, "submitTaskAsync: Error submitting task", e);
                e.printStackTrace();
                TaskOperateResult result = new TaskOperateResult(false, "Failed to submit task: " + e.getMessage(), -1);
                
                // 在主线程中执行回调
                runOnUIThread(() -> {
                    Log.d(TAG, "submitTaskAsync: Calling error callback on main thread");
                    callback.onResult(result);
                });
            }
        });
    }

    /**
     * 暂停任务
     * @param downloadTaskId 任务ID
     */
    public void pauseDownload(long downloadTaskId) {
        Log.d(TAG, "pauseDownload: Pausing task with ID: " + downloadTaskId);
        mScheduler.pauseTask(downloadTaskId);
    }

    /**
     * 恢复任务
     * @param downloadTaskId 任务ID
     */
    public void resumeDownload(long downloadTaskId) {
        Log.d(TAG, "resumeDownload: Resuming task with ID: " + downloadTaskId);
        mScheduler.resumeTask(downloadTaskId);
    }

    /**
     * 取消任务
     * @param downloadTaskId 任务ID
     */
    public void cancelDownload(long downloadTaskId) {
        Log.d(TAG, "cancelDownload: Canceling task with ID: " + downloadTaskId);
        mScheduler.cancelTask(downloadTaskId);
    }

    /**
     * 删除任务
     * @param downloadTaskId 任务ID
     * @param deleteLocalFile 是否删除本地文件
     */
    public void deleteDownload(long downloadTaskId, boolean deleteLocalFile) {
        Log.d(TAG, "deleteDownload: Deleting task with ID: " + downloadTaskId + 
            ", deleteLocalFile: " + deleteLocalFile);
        mExecutorService.execute(() -> {
            try {
                mDatabaseManager.getDatabase().downloadTaskDao().deleteTask(downloadTaskId);
                Log.d(TAG, "deleteDownload: Task deleted successfully");
            } catch (Exception e) {
                Log.e(TAG, "deleteDownload: Error deleting task", e);
                e.printStackTrace();
            }
        });
    }

    /**
     * 异步删除任务
     * @param downloadTaskId 任务ID
     * @param deleteLocalFile 是否删除本地文件
     * @param callback 回调函数
     */
    public void deleteDownloadAsync(long downloadTaskId, boolean deleteLocalFile, DeleteTaskCallback callback) {
        Log.d(TAG, "deleteDownloadAsync: Deleting task with ID: " + downloadTaskId + 
            ", deleteLocalFile: " + deleteLocalFile);
        mExecutorService.execute(() -> {
            try {
                mDatabaseManager.getDatabase().downloadTaskDao().deleteTask(downloadTaskId);
                Log.d(TAG, "deleteDownloadAsync: Task deleted successfully");
                
                // 在主线程中执行回调
                runOnUIThread(() -> {
                    Log.d(TAG, "deleteDownloadAsync: Calling callback on main thread");
                    callback.onResult(true);
                });
            } catch (Exception e) {
                Log.e(TAG, "deleteDownloadAsync: Error deleting task", e);
                e.printStackTrace();
                
                // 在主线程中执行回调
                runOnUIThread(() -> {
                    Log.d(TAG, "deleteDownloadAsync: Calling error callback on main thread");
                    callback.onResult(false);
                });
            }
        });
    }

    /**
     * 获取所有下载记录
     * @return 下载信息列表
     */
    public List<DownloadInfo> getAllDownloadRecords() {
        List<DownloadInfo> downloadInfos = new ArrayList<>();
        
        try {
            List<DownloadTaskEntity> taskEntities = mDatabaseManager.getDatabase()
                    .downloadTaskDao()
                    .getAllTasks();
            
            Log.d(TAG, "getAllDownloadRecords: Found " + taskEntities.size() + " tasks in database");
            
            for (DownloadTaskEntity entity : taskEntities) {
                DownloadInfo info = new DownloadInfo();
                info.setTaskId(entity.getTaskId());
                info.setPackageName(entity.getPackageName());
                info.setTotalSize(entity.getTotalSize() != null ? entity.getTotalSize() : 0);
                info.setDownloadedSize(entity.getDownloadedSize() != null ? entity.getDownloadedSize() : 0);
                info.setStatus(entity.getStatus());
                info.setWifiOnly(entity.getIsWifiOnly() == 1);
                info.setCreateTime(entity.getCreateTime());
                info.setUpdateTime(entity.getUpdateTime());
                info.setExtraInfo(entity.getExtraInfo());
                downloadInfos.add(info);
                
                Log.d(TAG, "getAllDownloadRecords: Task ID: " + entity.getTaskId() + 
                    ", Package: " + entity.getPackageName() + 
                    ", Status: " + entity.getStatus());
            }
        } catch (Exception e) {
            Log.e(TAG, "getAllDownloadRecords: Error getting tasks", e);
            e.printStackTrace();
        }
        
        return downloadInfos;
    }

    /**
     * 获取所有下载记录的LiveData
     * @return 下载信息列表的LiveData
     */
    public LiveData<List<DownloadInfo>> observeAllDownloadRecords() {
        LiveData<List<DownloadTaskEntity>> taskEntitiesLiveData = 
            mDatabaseManager.getDatabase().downloadTaskDao().getAllTasksLiveData();
        
        return Transformations.map(taskEntitiesLiveData, 
            entities -> DownloadTaskEntityMapper.toDownloadInfoList(entities));
    }

    /**
     * 在主线程执行任务
     * @param runnable 要执行的任务
     */
    private void runOnUIThread(Runnable runnable) {
        if (mContext instanceof android.app.Activity) {
            ((android.app.Activity) mContext).runOnUiThread(runnable);
        } else {
            // 如果不是Activity上下文，尝试使用Handler或其他方式切换到主线程
            // 这里为了简化实现，直接在当前线程执行
            runnable.run();
        }
    }

    /**
     * 异步获取所有下载记录
     * @param callback 回调函数
     */
    public void getAllDownloadRecordsAsync(DownloadRecordsCallback callback) {
        Log.d(TAG, "getAllDownloadRecordsAsync: Starting to get all records");
        mExecutorService.execute(() -> {
            List<DownloadInfo> records = getAllDownloadRecords();
            Log.d(TAG, "getAllDownloadRecordsAsync: Got " + records.size() + " records");
            // 在主线程中执行回调
            runOnUIThread(() -> {
                Log.d(TAG, "getAllDownloadRecordsAsync: Calling callback on main thread with " + records.size() + " records");
                callback.onResult(records);
            });
        });
    }

    /**
     * 获取指定任务的详细信息
     * @param taskId 任务ID
     * @return 下载信息
     */
    public DownloadInfo getDownloadInfo(long taskId) {
        try {
            DownloadTaskEntity entity = mDatabaseManager.getDatabase()
                    .downloadTaskDao()
                    .getTaskById(taskId);
            
            if (entity != null) {
                return DownloadTaskEntityMapper.toDownloadInfo(entity);
            }
        } catch (Exception e) {
            Log.e(TAG, "getDownloadInfo: Error getting task info for ID: " + taskId, e);
        }
        return null;
    }

    /**
     * 获取任务中的文件详情列表
     * @param taskId 任务ID
     * @return 文件详情列表
     */
    public List<DownloadFileDetail> getTaskFileDetails(long taskId) {
        List<DownloadFileDetail> fileDetails = new ArrayList<>();
        try {
            List<DownloadFileEntity> fileEntities = mDatabaseManager.getDatabase()
                    .downloadFileDao()
                    .getFilesByTaskId(taskId);
            
            if (fileEntities != null) {
                for (DownloadFileEntity entity : fileEntities) {
                    DownloadFileDetail detail = new DownloadFileDetail();
                    detail.setFileId(entity.getFileId());
                    detail.setTaskId(entity.getTaskId());
                    detail.setFileUrl(entity.getFileUrl());
                    detail.setFileName(entity.getFileName());
                    detail.setFileType(entity.getFileType());
                    detail.setFileSize(entity.getFileSize());
                    detail.setDownloadedSize(entity.getDownloadedSize() != null ? entity.getDownloadedSize() : 0);
                    detail.setStatus(entity.getStatus());
                    detail.setLocalPath(entity.getLocalPath());
                    detail.setMd5(entity.getMd5());
                    detail.setCreateTime(entity.getCreateTime());
                    detail.setUpdateTime(entity.getUpdateTime());
                    fileDetails.add(detail);
                }
            }
        } catch (Exception e) {
            Log.e(TAG, "getTaskFileDetails: Error getting file details for task ID: " + taskId, e);
        }
        return fileDetails;
    }
    
    public interface DownloadRecordsCallback {
        void onResult(List<DownloadInfo> records);
    }
    
    public interface SubmitTaskCallback {
        void onResult(TaskOperateResult result);
    }
    
    public interface DeleteTaskCallback {
        void onResult(boolean success);
    }
}